package com.swt.gap.service.impl;

import com.swt.gap.common.constant.GraphDbConstant;
import com.swt.gap.common.graph.GraphNeo4jVO;
import com.swt.gap.common.graph.GraphProcessor;
import com.swt.gap.common.graph.Neo4jTools;
import com.swt.gap.model.vo.FlowVO;
import com.swt.gap.model.vo.graph.LiteLink;
import com.swt.gap.service.TransactionService;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * 请填写说明
 *
 * @author sx
 * @date 2020/7/3 15:11
 */
@Service
public class TransactionServiceImpl implements TransactionService {

    private final static String TRANSACTION_EVENT = "交易事件";
    private final static String TRANSACTION_TYPE = "交易类型";
    private final static String TRANSACTION_TYPE_ALL = "全部";
    private final static String ACCOUNT_FROM = "主账号";
    private final static String ACCOUNT_FROM2 = "主卡号";
    private final static String ACCOUNT_TO = "对手账号";
    private final static String TRANSACTION_AMOUNT = "交易金额";

    private final Neo4jTools neo4jTools;

    public TransactionServiceImpl(Neo4jTools neo4jTools) {
        this.neo4jTools = neo4jTools;
    }

    @Override
    public Set<String> listTransactionType(List<LiteLink> links) {
        Set<String> retValue = new HashSet<>();
        retValue.add(TRANSACTION_TYPE_ALL);
        links.forEach(link -> {
            String startNodeId = link.getStartNodeId();
            String endNodeId = link.getEndNodeId();
            String cypher = "MATCH (s{id:'" + startNodeId + "'})--(e:" + TRANSACTION_EVENT + ")--(t{id:'"
                    + endNodeId + "'}) RETURN e." + TRANSACTION_TYPE + " as res";
            List<Object> values = neo4jTools.getOneResultByCypher(cypher);
            values.forEach(value -> retValue.add((String) value));
        });
        return retValue;
    }

    @Override
    public List<GraphNeo4jVO.Link> listFlow(FlowVO record) {
        List<GraphNeo4jVO.Link> retValue = new ArrayList<>();
        record.getLinks().forEach(link -> {

            String startNodeId = link.getStartNodeId();
            String endNodeId = link.getEndNodeId();
            String transactionType = record.getTransactionType();
            String cypherWhere = "";
            if (null != transactionType && !TRANSACTION_TYPE_ALL.equals(transactionType)) {
                cypherWhere = " and e." + TRANSACTION_TYPE + "='" + transactionType + "'";
            }
            String cypher = "match (s)--(e:`" + TRANSACTION_EVENT + "`)--(t) where s.id='" + startNodeId + "' and t.id='"
                    + endNodeId + "' " + cypherWhere + " return LABELS(s) as res1, LABELS(t) as res2, sum(toFloat(e.`" + TRANSACTION_AMOUNT + "`)) as res3";
            List<Object> results = neo4jTools.getThreeResultByCypher(cypher);
            if (results.size() > 2) {
                List<String> labelsNode1 = (ArrayList<String>) results.get(0);
                List<String> labelsNode2 = (ArrayList<String>) results.get(1);
                Double totalAmount = (Double) results.get(2);
                // 默认第一个节点是主账号 第二个节点是对手账号
                String fromNodeId = startNodeId;
                String toNodeId = endNodeId;
                //如果 第二个节点label是主账号 则翻转
                for (String label : labelsNode2) {
                    if (ACCOUNT_FROM.equals(label) || ACCOUNT_FROM2.equals(label)) {
                        String tmp = fromNodeId;
                        fromNodeId = toNodeId;
                        toNodeId = tmp;
                        break;
                    }
                }

                GraphNeo4jVO.Link retLink;
                int weight = 1;
                if (record.getWeight()) {
                    double absTotalAmount = Math.abs(totalAmount);
                    if (absTotalAmount > 1000000) {
                        weight = 4;
                    } else if (absTotalAmount > 100000) {
                        weight = 3;
                    } else if (absTotalAmount > 10000) {
                        weight = 2;
                    }
                }

                Map<String, Object> props = new HashMap<>();
                props.put(GraphDbConstant.PROPERTY_AMOUNT, (new BigDecimal(totalAmount)).setScale(2, RoundingMode.HALF_UP).doubleValue());
//             如果交易金额大于0 则主账号净收，流向为从对手账号到主账号；否则相反
                if (totalAmount > 0) {
                    retLink = GraphNeo4jVO.Link.builder()
                            .id(link.getId())
                            .type(link.getType())
                            .properties(props)
                            .startNodeId(toNodeId)
                            .endNodeId(fromNodeId)
                            .weight(weight)
                            .build();
                } else {
                    retLink = GraphNeo4jVO.Link.builder()
                            .id(link.getId())
                            .type(link.getType())
                            .properties(props)
                            .startNodeId(fromNodeId)
                            .endNodeId(toNodeId)
                            .weight(weight)
                            .build();
                }

                retValue.add(retLink);
            }
        });
        return retValue;
    }
}
